﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.ServiceModel;

using OCXS;
using OCXS.OCXSServiceLibrary.Administration;
using OCXS.OCXSServiceLibrary.Configuration;

namespace OCXS {

    namespace OCXSServiceLibrary {

        public partial class OCXSService {

            /// <summary>
            /// Used to directly fetch all variable entries.
            /// </summary>
            /// <remarks>
            /// The Administration Panel uses this service method in order to collect variable's
            /// current values.
            /// </remarks>
            /// <param name="request">Request object.</param>
            /// <returns>An object containing all variable identifiers, values, types and descriptions.</returns>
            public UpdateVariablesResponse UpdateVariables(UpdateVariablesRequest request) {

                List<string> varIds = new List<string>();
                List<float> varValues = new List<float>();
                List<string> varTypes = new List<string>();
                List<string> varDescs = new List<string>();

                // Get variables from data store.
                foreach (KeyValuePair<VariableType, object> el in this.dataStore.Values) {
                    // Safe data retrieve.
                    varIds.Add(el.Key.VariablePath + el.Key.VariableName);
                    varTypes.Add(el.Key.VariableT.ToString());
                    varDescs.Add(el.Key.VariableDescription);
                    
                    // Critical section.
                    lock (el.Value) {
                        varValues.Add((float)el.Key.VariableValue);
                    }
                }

                UpdateVariablesResponse uvr = new UpdateVariablesResponse(
                    varIds.ToArray(), 
                    varValues.ToArray(),
                    varTypes.ToArray(),
                    varDescs.ToArray());
                return uvr;

            }

            /// <summary>
            /// Used to directly fetch all subscription entries.
            /// </summary>
            /// <remarks>
            /// The Administration Panel uses this service method in order to collect subscription information.
            /// </remarks>
            /// <param name="request">Request object.</param>
            /// <returns>An object containing subscription identifiers, disposed status and subscribed variables.</returns>
            public UpdateSubscriptionsResponse UpdateSubscriptions(UpdateSubscriptionRequest request) {

                List<string> sids = new List<string>();
                List<bool> dispd = new List<bool>();
                List<string[]> variables = new List<string[]>();

                lock (this.subscriptionTablePadlock) {
                    foreach (KeyValuePair<string, SubscriptionRecord> el in this.subscriptionTable) {

                        // Gather SIDs, disposed status and Watched variable ids.
                        sids.Add(el.Key);
                        dispd.Add(el.Value.Disposed);
                        variables.Add(el.Value.WatchedVariables);
                    
                    }
                }

                return new UpdateSubscriptionsResponse(sids.ToArray(), dispd.ToArray(), variables.ToArray());
            }

            /// <summary>
            /// Used to directly fetch all server status information. 
            /// </summary>
            /// <remarks>
            /// The Administration Panel uses this service method in order to collect server status information.
            /// </remarks>
            /// <param name="request">Request object.</param>
            /// <returns>An object containing server status information.</returns>
            public UpdateServerStatusResponse UpdateServerStatus(UpdateServerStatusRequest request) {

                int varNum = this.dataStore.Count;
                int subWatcherTNum = 0;
                int subNum = 0;
                int genTNum = 0;
                long gcTotMem = 0L;
                int gcCollNum = 0;

                lock (this.subscriptionTablePadlock) {
                    subNum = this.subscriptionTable.Count;
                    foreach (SubscriptionRecord sr in this.subscriptionTable.Values) {
                        subWatcherTNum += sr.WatchedVariables.Length;
                    }
                }

                genTNum = this.threadPool.Count;

                gcTotMem = GC.GetTotalMemory(false);

                for (int i = 0; i <= GC.MaxGeneration; i++)
                    gcCollNum += GC.CollectionCount(i);

                UpdateServerStatusResponse USSR = 
                    new UpdateServerStatusResponse(varNum, subWatcherTNum, subNum, genTNum, gcTotMem, gcCollNum);

                return USSR;
            }

        }

    } /* OCXSServiceLibrary */

} /* OCXS */
